/* Tyler Brock 2010 -- Options tools */
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <gsl/gsl_cdf.h>
#include <string.h>
#ifndef Pi 
#define Pi 3.141592653589793238462643 
#endif 

typedef struct {
  double risk_free_rate;
  double volatility;
} market;

typedef struct {
  int month;
  int day;
  int year;
} date;

typedef struct {
  date d;
  double v;
} date_val;

typedef struct {
  int count;
  date_val *ts;
} time_series;


double calc_d1(double s, double k, double r, double t, double v);
double calc_d2(double d1, double t, double v);
double black_scholes(int c, double s, double k, double r, double t, double v); 
double cnd(double z); /*cumulative normal distribution (gaussian)*/
double cnd_manual(double x); /*cumulative normal distribution */
void printTime(void); /*prints current local time*/
time_series load_time_series(FILE *fp);

enum option_type {put, call};
enum month {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};

int main(int argc, char *argv[])
{
  double spot = 53.0;
  double strike = 50.0;
  double time_to_maturity = 28.0/365.0;
  char config_buffer[1024];
  char var_buffer[1024];
  double value_buffer;
  market m;
  FILE *config;
  int linenum = 0;

  //m.risk_free_rate = 0.01;
  //m.volatility = 0.2;

  //open config file for reading
  if(argc < 2)
  {
    fprintf(stderr, "Usage: %s config\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  else
  {
    if ((config = fopen(argv[1], "r")) == NULL)
    {
      fprintf(stderr, "Couln't open file %s\n", argv[1]);
      exit(EXIT_FAILURE);
    }
  }

  printf("Reading config file...\n");
  while(fgets(config_buffer, 1024, config) != NULL)
  {
    linenum++;
    if(config_buffer[0] == '#') continue;

    if (sscanf(config_buffer,"%s = %lf",var_buffer,&value_buffer) != 2)
    // read a string then a double seperated by an "=" sign
    {
      fprintf(stderr, "Syntax error, line %d\n", linenum);
      printf("var_buffer=%s\n",var_buffer);
      printf("value_buffer=%lf\n",value_buffer);
      continue;
    }
    else if (strcmp(var_buffer,"risk_free_rate") == 0)
    {
      printf("->Read risk_free_rate\n");
      m.risk_free_rate = value_buffer;
    }
    else if (strcmp(var_buffer,"volatility") == 0)
    {
      printf("->Read volatility\n");
      m.volatility = value_buffer;
    }
  }
  fclose(config);
  printf("Done reading config file. %d lines processed\n", linenum);
  
  printTime();

  double price = black_scholes(call, spot, strike, m.risk_free_rate, time_to_maturity, m.volatility);
  double pricep = black_scholes(put, spot, strike, m.risk_free_rate, time_to_maturity, m.volatility);
  printf("Price is %.4lf\n", price);
  printf("Price is %.4lf\n", pricep);

  return EXIT_SUCCESS;
}

void printTime(void)
{
  time_t rawtime;
  struct tm *timeinfo;
  time ( &rawtime );
  timeinfo = localtime ( &rawtime );
  printf("Current local time and date: %s", asctime(timeinfo));
}

double calc_d1(double s, double k, double r, double t, double v)
{
  return (log(s / k) + (r + v * v / 2) * t) / (v * sqrt(t));
}

double calc_d2(double d1, double t, double v)
{
  return d1 - v * sqrt(t);
}

double cnd(double z)
{
  return gsl_cdf_gaussian_P(z, 1);
}

double black_scholes(int isCall, double s, double k, double r, double t, double v)
{
  double price;
  double d1 = calc_d1(s, k, r, t, v);
  double d2 = calc_d2(d1, t, v);
  if (isCall)
    {
      price = s * cnd(d1) - (k * exp(-r * t) * cnd(d2));    
    }
  else
    {
      price = k * exp(-r * t) * cnd(-d2) - s * cnd(-d1);
    }
  return price;
}

double manual_cnd(double X)
{
  double L, K, w ;
  /* constants */
  double const a1 = 0.31938153, a2 = -0.356563782, a3 = 1.781477937;
  double const a4 = -1.821255978, a5 = 1.330274429;

  L = fabs(X);
  K = 1.0 / (1.0 + 0.2316419 * L);
  w = 1.0 - 1.0 / sqrt(2 * Pi) * exp(-L *L / 2) * (a1 * K + a2 * K *K + a3 * pow(K,3) + a4 * pow(K,4) + a5 * pow(K,5));

  if (X < 0 ){
    w= 1.0 - w;
  }
  return w;
}
